package com.chiefumpire;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class OverprintingSimulateStream extends InputStream {
	private InputStream delegate;
	private int cursor = 0;
	private boolean eol = false;
	private ArrayList<Integer> line = new ArrayList<Integer>();

	private final static int CHAR_FORM_FEED = 12;
	private final static int CHAR_CARRIAGE_RETURN = '\r';
	private final static int CHAR_LINE_FEED = '\n';

	public OverprintingSimulateStream(InputStream input) {
		if (input == null) {
			throw new IllegalArgumentException("must supply input");
		}
		this.delegate = input;
	}

	@Override
	public int read() throws IOException {
		if (eol == false) {
			readLine();
			return getCharFromLine();
		} else {
			return getCharFromLine();
		}
	}

	private int getCharFromLine() {
		int b = line.get(cursor);
		cursor++;
		if (cursor >= line.size()) {
			cursor = 0;
			eol = false;
			line.clear();
		}
		return b;
	}

	private void println() {
		line.add(CHAR_CARRIAGE_RETURN);
		line.add(CHAR_LINE_FEED);
		eol = true;
		cursor = 0;
	}

	private void readLine() throws IOException {
		int b = -1;
		while ((b = delegate.read()) != -1) {
			// System.out.print((char) b);
			processChar(b);
			if (eol) {
				break;
			}
		}
		if (b == -1) {
			eol = true;
			line.add(-1);
		}
	}

	private void processChar(int b) throws IOException {
		switch (b) {
		case CHAR_FORM_FEED:
			println();
			line.add(CHAR_FORM_FEED);
			break;
		case CHAR_LINE_FEED:
			println();
			break;
		case CHAR_CARRIAGE_RETURN:
			cursor = 0;
			break;
		default:
			addCharToLine(b);
			break;
		}
	}

	private void addCharToLine(int b) {
		if (cursor == line.size()) {
			line.add(b);
		} else {
			if (isVisible(line.get(cursor)) == false) {
				line.set(cursor, b);
			}
		}
		cursor++;
	}

	private boolean isVisible(int b) {
		if (b >= 33 && b <= 126) {
			return true;
		}
		return false;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		String path = "sample.txt";
		String outputPath = "output.txt";
		FileInputStream fileInput = new FileInputStream(path);
		InputStream transformedInput = new OverprintingSimulateStream(fileInput);

		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(outputPath));

		int bufferSize = 64 * 1024;
		byte[] buffer = new byte[bufferSize];

		int read = -1;
		while ((read = transformedInput.read(buffer)) != -1) {
			bos.write(buffer, 0, read);
		}
		bos.flush();
		bos.close();
	}
}
